#pragma once

#include<iostream>
#include<sys/types.h>
#include<sys/socket.h>
#include"Comm.hpp"
#include"Logger.hpp"
#include<netinet/in.h>
#include<arpa/inet.h>
#include<string.h>
#include"InetAddr.hpp"
#include<unistd.h>
#include<sys/wait.h>
#include<pthread.h>
#include"ThreadPool.hpp"
#include<functional>

using task_t = std::function<void()>;

class TcpServer
{
private:
    void HandlerIO(int socket_fd, InetAddr client)
    {
        char buffer[1024];
        while(true)
        {
            int read_ret = read(socket_fd, buffer, sizeof(buffer) - 1);
            if(read_ret > 0)
            {
                buffer[read_ret] = 0;
                std::string echo = "server echo# ";
                echo += buffer;
                LOG(LogLevel::DEBUG) << client.ToString() << "say: " << buffer;
                write(socket_fd, echo.c_str(), echo.size());
            }
            else if(read_ret == 0)
            {
                LOG(LogLevel::INFO) << "client " << client.ToString() << " quit";
                break;
            }
            else
            {
                LOG(LogLevel::INFO) << "read client " << client.ToString() 
                                    << " error, socket_fd:" << socket_fd;
                break;
            }
        }
        close(socket_fd);
    }
public:
    TcpServer(uint16_t port = 8080)
        :_listen_socket_fd(-1)
        ,_port(port)
    { }   

    void Init()
    {
        _listen_socket_fd = socket(AF_INET, SOCK_STREAM, 0);
        if(_listen_socket_fd < 0)
        {
            LOG(LogLevel::FATAL) << "create socket error";
            exit(SOCKET_CREATE_ERROR);
        }   
        LOG(LogLevel::INFO) << "create socket success:" << _listen_socket_fd;
        // struct sockaddr_in local;
        // memset(&local, 0, sizeof(local));
        // local.sin_family = AF_INET;
        // local.sin_port = htons(_port);
        // local.sin_addr.s_addr = htonl(INADDR_ANY);
        InetAddr local(_port);
        int bind_ret = bind(_listen_socket_fd, local.Addr(), local.Len());
        if(bind_ret < 0)
        {
            LOG(LogLevel::FATAL) << "bind socket error";
            exit(SOCKET_BIND_ERROR);
        }
        LOG(LogLevel::INFO) << "bind socket success:" << _listen_socket_fd;
        int listen_ret = listen(_listen_socket_fd, 8);
        if(listen_ret < 0)
        {
            LOG(LogLevel::FATAL) << "listen socket error";
            exit(SOCKET_LISTEN_ERROR);
        }
        LOG(LogLevel::INFO) << "listen socket success:" << _listen_socket_fd;
    }

    class ThreadData
    {
    public:
        ThreadData(int socket_fd, TcpServer* self, const InetAddr& addr)
            :_socket_fd(socket_fd)
            ,_self(self)
            ,_addr(addr)
        { }

    public:
        int _socket_fd;
        TcpServer* _self;
        InetAddr _addr;
    };

    static void* Routine(void* args)
    {
        ThreadData* td = static_cast<ThreadData*>(args);
        pthread_detach(pthread_self());
        td->_self->HandlerIO(td->_socket_fd, td->_addr);
        delete td;
        return nullptr;
    }

    void Start()
    {
        while(true)
        {
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int socket_fd = accept(_listen_socket_fd, (struct sockaddr*)&peer, &len);
            if(socket_fd < 0)
            {
                LOG(LogLevel::WARNING) << "accept client socket error";
                continue;
            }
            InetAddr client(peer);
            LOG(LogLevel::INFO) << "获取新连接成功, socket_fd is " << socket_fd 
                                << " client addr: " << client.ToString();
            //HandlerIO(socked_fd, client);
            // pid_t pid = fork();
            // if(pid < 0)
            // {
            //     LOG(LogLevel::FATAL) << "资源不足，创建子进程失败";
            //     exit(CREATE_CHILD_PORCESS_ERROR);
            // }
            // else if(pid == 0)
            // {
            //     close(_listen_socket_fd);
            //     if(fork() > 0)
            //         exit(OK);
            //     HandlerIO(socket_fd, client);
            //     exit(OK);
            // }
            // else
            // {
            //     close(socket_fd);
            //     int waitpid_ret = waitpid(pid, nullptr, 0);
            // }
            // pthread_t tid;
            // ThreadData* td = new ThreadData(socket_fd, this, client);
            // pthread_create(&tid, nullptr, Routine, (void*)td);
            ThreadPool<task_t>::GetInstance()->EnQueue
            (
                [this, socket_fd, client]()
                {
                    this->HandlerIO(socket_fd, client);
                }
            );
        }
    }

private:
    int _listen_socket_fd;
    uint16_t _port;
};